package com.kx.smartdevice.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kx.smartdevice.cache.CategoriesCache;
import com.kx.smartdevice.constants.ResultCode;
import com.kx.smartdevice.event.ColorEvent;
import com.kx.smartdevice.event.DeviceStatusEvent;
import com.kx.smartdevice.event.DeviceStatusType;
import com.kx.smartdevice.event.PowerEvent;
import com.kx.smartdevice.exceptions.AddErrorException;
import com.kx.smartdevice.exceptions.DeleteErrorException;
import com.kx.smartdevice.exceptions.QueryErrorException;
import com.kx.smartdevice.exceptions.UpdateErrorException;
import com.kx.smartdevice.mapper.DeviceMapper;
import com.kx.smartdevice.pojo.Category;
import com.kx.smartdevice.pojo.Device;
import com.kx.smartdevice.service.CategoryService;
import com.kx.smartdevice.service.DeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * @ClassName DevicesServiceImpl
 * @Author Sun
 * @Date 2021/6/1 14:21
 */
@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private CategoryService categoryService;
    @Autowired
    private CategoriesCache categoriesCache;
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private ApplicationContext context;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public PageInfo<Device> getAllDevices(int page, int limit, String address, Integer status, int direction, int areaid, int categoryid) {
        PageHelper.startPage(page, limit);
        try {
            List<Device> deviceList = deviceMapper.getAllDevices(address, status, direction, areaid, categoryid);
//            context.publishEvent(deviceList);//发布事件,更新设备的在线状态,因为直接修改的数据的属性,所以对象不变,可以交给异步处理
            deviceList.forEach(device -> {
//                WebSocketSession session = DevicePowerWebSocketHandler.getClient(device.getDevicesuuid());
//                if (session != null && session.isOpen()) {
//                    device.setStatus("1");//设置在线
//                }

                device.setCategory(categoryService.getCategoryById(device.getCategoryid()));//设置分类对象,主要目的是在页面显示操作命令
            });
            return new PageInfo<>(deviceList);
        } catch (Exception e) {
            e.printStackTrace();
            throw new QueryErrorException("查询异常", ResultCode.ERROR);
        }
    }

    @Override
    public void AddDevice(Device device) {
        if (device == null || device.isEmpty()) {
            throw new AddErrorException("数据不能为空", ResultCode.NULL_DATA);
        }
        try {
            deviceMapper.AddDevice(device);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AddErrorException("添加失败", ResultCode.ERROR);
        }

    }


    @Override
    public void updateDevice(Device device) {
        if (device == null || device.isEmpty()) {
            throw new UpdateErrorException("数据为空", ResultCode.NULL_DATA);
        }
        try {
            deviceMapper.updateDevice(device);
        } catch (Exception e) {
            e.printStackTrace();
            throw new UpdateErrorException("更新失败", ResultCode.ERROR);
        }
    }


    @Override
    public void deleteDevices(String[] ids) {
        if (ids == null || ids.length == 0) {
            throw new DeleteErrorException("没有传递 id", ResultCode.ERROR);
        }

        try {
            deviceMapper.deleteDevices(ids);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DeleteErrorException("删除失败", ResultCode.ERROR);
        }
    }

    @Override
    public Device getDeviceById(Long id) {
        if (id == null || id == 0) {
            throw new QueryErrorException("数据为空", ResultCode.NULL_DATA);
        }

        try {
            Device device = deviceMapper.getDeviceById(id);
            if (device == null) {
                throw new QueryErrorException("查询失败", ResultCode.ERROR);
            }
//            WebSocketSession session = DevicePowerWebSocketHandler.getClient(device.getDevicesuuid());
//            if (session != null && session.isOpen()) {
//                device.setStatus("1");//设置在线
//            }
            context.publishEvent(device);//更新设备状态
            return device;
        } catch (Exception e) {
            e.printStackTrace();
            throw new QueryErrorException("查询失败", ResultCode.ERROR);

        }
    }

    @Override
    public void sendControl(String uuid, String command) {
        //我们需要完成的操作
        //分析下我们需要做什么
        //我们需要知道操作发送到哪个设备,uuid 就是我们的设备的唯一标识
        //我们要发送的内容是什么?我们不同类型的设备会出现发送不同数据的情况,需要根据设备找到与之相关的分类,再获取到所有的指令,然后看看当前的命令实际上要执行的指令是什么

        //先根据设备的 uuid 找到所属的分类的 id,因为我们要做的事情命令都在分类上
        Long categoryId = deviceMapper.getCategoryIdByUUID(uuid);
        //然后通过分类id拿到需要操作的明令
        Category category = categoriesCache.get(categoryId);
        if (category != null) {
            String txcommand = category.getTxcommand();
            try {
                //把拿到的json数据解析成map
                Map map = objectMapper.readValue(txcommand, Map.class);
               /*  {   "open": { "type": 1, "value": "0" },
                    "close": { "type": 1, "value": "1" },
                    "change": { "type": 2, "value": "2" }
                   }
                   type代表是控制开关灯的芯片(1)还是控制变色的芯片(2)
                   value代表需要执行的明令0开灯  1关灯  2 变色
                */
                //通过key也就是command，拿到需要执行的命令，但是命令里面还是一个map
                Object o = map.get(command);
                if (o instanceof Map) {
                    Integer type = (Integer) ((Map) o).get("type");
                    //这个才是真正要发出去的命令
                    String value = (String) ((Map) o).get("value");
                    if (1 == type) {//说明是控制开关灯
                        //发布PowerEvent事件，让PowerCommandWebSocket进行处理
                        context.publishEvent(new PowerEvent(uuid, value));
                    } else if (2 == type) {//说明是变色
                        //发布ColorEvent事件，让ColorCommandWebSocket进行处理
                        context.publishEvent(new ColorEvent(uuid, value));
                    } else {
                        //其他操作
                    }
                }

            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }

    //在这里处理更新设备状态的事件
    @EventListener
    public void OnEvent(DeviceStatusEvent event) {
        String uuid = event.getUuid();
        DeviceStatusType type = event.getType();
        switch (type) {
            case OPEN:
                //更新为在线状态
                deviceMapper.updateoffLine(uuid,"1");
                break;
            case CLOSE:
                //更新为离线状态
                deviceMapper.updateoffLine(uuid,"0");
                break;
        }
    }
}
